This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Ctrl+Shift+Enter.

plot(cars)
library(ggplot2)

library(dplyr)

Attaching package: <U+393C><U+3E31>dplyr<U+393C><U+3E32>

The following objects are masked from <U+393C><U+3E31>package:stats<U+393C><U+3E32>:

    filter, lag

The following objects are masked from <U+393C><U+3E31>package:base<U+393C><U+3E32>:

    intersect, setdiff, setequal, union
setwd("C:\\Users\\Revanth K\\Documents\\coupon purchase prediction")

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Ctrl+Alt+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K to preview the HTML file). ‘’’{r} setwd(“D:DMpurchase prediction”) ‘’’

#read in all the input data
cpdtr <- read.csv("coupon_detail_train.csv")
cpltr <- read.csv("coupon_list_train.csv")
cplte <- read.csv("coupon_list_test.csv")
ulist <- read.csv("user_list.csv")
cpatr <- read.csv("coupon_area_train.csv", stringsAsFactors = FALSE)
cpvtr <- read.csv("coupon_visit_train.csv", stringsAsFactors = FALSE)
cpdtr <- read.csv("coupon_detail_train.csv", stringsAsFactors = FALSE)
barplot(table(ulist$SEX_ID),
        names.arg = c("FEMALE", "MALE"),main = "gender distributiion",col = "#ffd1dc")

hist(ulist$AGE,main = "Age- distribution",xlab= NULL,col="#aec6cf")

age_groups <- c(20, 30, 40, 50, 60, 70, 80)
ulist$AGE_GROUP <- cut(ulist$AGE, age_groups, include.lowest = TRUE)
plot(ulist$AGE_GROUP,ulist$SEX_ID, main = "Age Group and Gender", xlab = "Age Group", ylab = "Gender")

names(ulist)
[1] "REG_DATE"      "SEX_ID"        "AGE"           "WITHDRAW_DATE"
[5] "PREF_NAME"     "USER_ID_hash"  "AGE_GROUP"    
par(mfrow=c(1,1))
library(ggplot2)
ggplot(ulist, aes(x=AGE, fill=SEX_ID)) +
  geom_histogram(binwidth=5, position="dodge")

Registered date (by sex_id

### Registered date (by sex_id
ulist$REG_DATE <- as.Date(ulist$REG_DATE)
ulist$WITHDRAW_DATE <- as.Date(ulist$WITHDRAW_DATE)
ggplot(ulist, aes(x=ulist$REG_DATE, fill=SEX_ID)) +
  geom_histogram(binwidth=25, position="dodge")

ggplot(ulist, aes(x=ulist$WITHDRAW_DATE, fill=SEX_ID)) +
  geom_histogram(binwidth=25, position="dodge")

NA

Membership duration

ulist$LAST_DATE <- ulist$WITHDRAW_DATE
ulist[is.na(ulist$LAST_DATE),]$LAST_DATE <- max(ulist[is.na(ulist$WITHDRAW_DATE) == FALSE,]$WITHDRAW_DATE)
ulist$DURATION <- ulist$LAST_DATE - ulist$REG_DATE
ulist$DURATION <- as.numeric(ulist$DURATION, units = "days")
summary(ulist$DURATION)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    1.0   197.0   353.0   345.1   493.0   711.0 
ggplot(ulist, aes(x=ulist$DURATION, fill=SEX_ID)) +
  geom_histogram(binwidth=25, position="dodge")

user_frequency = as.data.frame.table(sort(table(ulist$PREF_NAME)))
colnames(user_frequency) <- c("PREF_NAME", "FREQUENCY")
print(user_frequency)
ABCDEFGHIJ0123456789
PREF_NAME
<fctr>
FREQUENCY
<int>
鳥取県25
福井県40
島根県41
秋田県50
高知県51
佐賀県55
和歌山県57
徳島県57
青森県57
山形県60
cpvtr$sex = ulist[match(cpvtr$USER_ID_hash,ulist$USER_ID_hash),"SEX_ID"]
purchased_gender <- table(cpvtr$PURCHASE_FLG,cpvtr$sex)

coupon userlist data exploration

barplot(prop.table(purchased_gender,1), legend.text = TRUE,
        main = "Purchages by Gender", 
        col = c("red","yellow"),
        beside = TRUE,
        xlab = "Purchased",
        ylab = "Proportion")

cpvtr$age = ulist[match(cpvtr$USER_ID_hash,ulist$USER_ID_hash),"AGE"]
purchased_age <- table(cpvtr$PURCHASE_FLG,cut(cpvtr$age,breaks = seq(10,100,by=10)))
barplot(purchased_age, legend.text = TRUE,
        main = "Purchages by Age", 
        col = c("red","yellow"),
        beside = TRUE,
        xlab = "Purchased",
        ylab = "Proportion")

cpdtr$age = ulist[match(cpdtr$USER_ID_hash,ulist$USER_ID_hash),"AGE"]
subset_age_10 = cpdtr[(as.numeric(cpdtr$age) > 10
                                     & as.numeric(cpdtr$age) <= 20) ,]
pie(table(subset_age_10$COUPON_ID_hash))

subset_age_20 = cpdtr[(as.numeric(cpdtr$age) > 20
                                     & as.numeric(cpdtr$age) <= 30) ,]
pie(table(subset_age_20$COUPON_ID_hash))

subset_age_30 = cpdtr[(as.numeric(cpdtr$age) > 30
                                     & as.numeric(cpdtr$age) <= 40) ,]
pie(table(subset_age_30$COUPON_ID_hash))

subset_age_40 = cpdtr[(as.numeric(cpdtr$age) > 40
                                     & as.numeric(cpdtr$age) <= 50) ,]
pie(table(subset_age_40$COUPON_ID_hash))

subset_age_50 = cpdtr[(as.numeric(cpdtr$age) > 50
                                     & as.numeric(cpdtr$age) <= 60) ,]
pie(table(subset_age_50$COUPON_ID_hash))

subset_age_60 = cpdtr[(as.numeric(cpdtr$age) > 60
                                     & as.numeric(cpdtr$age) <= 70) ,]
pie(table(subset_age_60$COUPON_ID_hash))

subset_age_70 = cpdtr[(as.numeric(cpdtr$age) > 70) ,]
pie(table(subset_age_70$COUPON_ID_hash))

### Coupon List
barplot(table(cpltr$USABLE_DATE_MON),
# names.args = c("No", "Yes")
main = "Coupon usable on Monday?",
col = "#fdfd96")

barplot(table(cpltr$USABLE_DATE_TUE),
        
        main = "Coupon usable on Tuesday?",
        col = "#fdfd96")

barplot(table(cpltr$USABLE_DATE_WED),
        
        main = "Coupon usable on Wednesday?",
        col = "#fdfd96")

barplot(table(cpltr$USABLE_DATE_THU),
        
        main = "Coupon usable on Thursday?",
        col = "#fdfd96")

barplot(table(cpltr$USABLE_DATE_FRI),
        
        main = "Coupon usable on Friday?",
        col = "#fdfd96")

barplot(table(cpltr$USABLE_DATE_SAT),
        
        main = "Coupon usable on Saturday?",
        col = "#fdfd96")

barplot(table(cpltr$USABLE_DATE_SUN),
        
        main = "Coupon usable on Sunday?",
        col = "#fdfd96")

The DISCOUNT PRICE seems interesting too, as commons strategy to attract buyers is to show large discounts. The outlier kind of distorts this graph, though.

ggplot(cpltr, aes(x = CATALOG_PRICE, y = DISCOUNT_PRICE)) + geom_point() + 
  labs(x = "Catalogue Price", y = "Discount Price", title = "Catalogue and Discount Prices")

Coupon Area

Coupons are listed in different prefectures (states).

barplot(table(cpatr$PREF_NAME),
        main = "Coupon Listing Areas (Prefectures)")

couponPrefectures <- as.data.frame(table(cpatr$PREF_NAME))
colnames(couponPrefectures) <- c("Prefecture", "Frequency")
arrange(couponPrefectures, desc(Frequency))
ABCDEFGHIJ0123456789
Prefecture
<fctr>
Frequency
<int>
東京都19720
大阪府6942
神奈川県6152
愛知県3275
福岡県3135
埼玉県3035
兵庫県3027
千葉県2922
北海道2715
京都府2697
#making of the train set
train <- merge(cpdtr,cpltr)
train <- train[,c("COUPON_ID_hash","USER_ID_hash",
                  "GENRE_NAME","DISCOUNT_PRICE","PRICE_RATE",
                  "USABLE_DATE_MON","USABLE_DATE_TUE","USABLE_DATE_WED","USABLE_DATE_THU",
                  "USABLE_DATE_FRI","USABLE_DATE_SAT","USABLE_DATE_SUN","USABLE_DATE_HOLIDAY",
                  "USABLE_DATE_BEFORE_HOLIDAY","large_area_name","ken_name","small_area_name")]
#combine the test set with the train
cplte$USER_ID_hash <- "dummyuser"
cpchar <- cplte[,c("COUPON_ID_hash","USER_ID_hash",
                   "GENRE_NAME","DISCOUNT_PRICE","PRICE_RATE",
                   "USABLE_DATE_MON","USABLE_DATE_TUE","USABLE_DATE_WED","USABLE_DATE_THU",
                   "USABLE_DATE_FRI","USABLE_DATE_SAT","USABLE_DATE_SUN","USABLE_DATE_HOLIDAY",
                   "USABLE_DATE_BEFORE_HOLIDAY","large_area_name","ken_name","small_area_name")]
train <- rbind(train,cpchar)
#NA imputation
train[is.na(train)] <- 1
#feature engineering
train$DISCOUNT_PRICE <- 1/log10(train$DISCOUNT_PRICE)
train$PRICE_RATE <- (train$PRICE_RATE*train$PRICE_RATE)/(100*100)
#convert the factors to columns of 0's and 1's
train <- cbind(train[,c(1,2)],model.matrix(~ -1 + .,train[,-c(1,2)],
                                           contrasts.arg=lapply(train[,names(which(sapply(train[,-c(1,2)], is.factor)==TRUE))], contrasts, contrasts=FALSE)))
#separate the test from train
test <- train[train$USER_ID_hash=="dummyuser",]
test <- test[,-2]
train <- train[train$USER_ID_hash!="dummyuser",]
#data frame of user characteristics
uchar <- aggregate(.~USER_ID_hash, data=train[,-1],FUN=mean)
uchar$DISCOUNT_PRICE <- 1
uchar$PRICE_RATE <- 1
#Weight Matrix: GENRE_NAME DISCOUNT_PRICE PRICE_RATE USABLE_DATE_ large_area_name ken_name small_area_name
library(Matrix)
require(Matrix)
W <- as.matrix(Diagonal(x=c(rep(2.05,13), rep(2,1), rep(-0.13,1), rep(0,9), rep(0.5,9), rep(1.01,47), rep(4.75,55))))
# We are goingto learn  is how to use a well-known similarity measure (Cosine similarity) to clacualte the similarity between different coupons
#STEP1: conver the dat to dot product in matrix format
# STEP2:
#calculation of cosine similairties of users and coupons
score = as.matrix(uchar[,2:ncol(uchar)]) %*% W %*% t(as.matrix(test[,2:ncol(test)]))
#order the list of coupons according to similairties and take only first 10 coupons
uchar$PURCHASED_COUPONS <- do.call(rbind, lapply(1:nrow(uchar),FUN=function(i){
  purchased_cp <- paste(test$COUPON_ID_hash[order(score[i,], decreasing = TRUE)][1:10],collapse=" ")
  return(purchased_cp)
}))
#make submission
submission <- merge(ulist, uchar, all.x=TRUE)
submission <- submission[,c("USER_ID_hash","PURCHASED_COUPONS")]
write.csv(submission, file="cosine_sim.csv", row.names=FALSE)
# Create master translation table from Japanese to English
coupon_list_train = read.csv("coupon_list_train.csv", as.is=T) # Source file the English list is keyed by
trans = data.frame(
  jp=unique(c(coupon_list_train$GENRE_NAME, coupon_list_train$CAPSULE_TEXT,
              coupon_list_train$large_area_name, coupon_list_train$ken_name,
              coupon_list_train$small_area_name)),
  en=c("Food","Hair salon","Spa","Relaxation","Beauty","Nail and eye salon","Delivery service","Lesson","Gift card","Other coupon","Leisure","Hotel and Japanese hotel","Health and medical","Other","Hotel","Japanese hotel","Vacation rental","Lodge","Resort inn","Guest house","Japanse guest house","Public hotel","Beauty","Event","Web service","Class","Correspondence course","Kanto","Kansai","East Sea","Hokkaido","Kyushu-Okinawa","Northeast","Shikoku","Chugoku","Hokushinetsu","Saitama Prefecture","Chiba Prefecture","Tokyo","Kyoto","Aichi Prefecture","Kanagawa Prefecture","Fukuoka Prefecture","Tochigi Prefecture","Osaka prefecture","Miyagi Prefecture","Fukushima Prefecture","Oita Prefecture","Kochi Prefecture","Hiroshima Prefecture","Niigata Prefecture","Okayama Prefecture","Ehime Prefecture","Kagawa Prefecture","Tokushima Prefecture","Hyogo Prefecture","Gifu Prefecture","Miyazaki Prefecture","Nagasaki Prefecture","Ishikawa Prefecture","Yamagata Prefecture","Shizuoka Prefecture","Aomori Prefecture","Okinawa","Akita","Nagano Prefecture","Iwate Prefecture","Kumamoto Prefecture","Yamaguchi Prefecture","Saga Prefecture","Nara Prefecture","Mie","Gunma Prefecture","Wakayama Prefecture","Yamanashi Prefecture","Tottori Prefecture","Kagoshima prefecture","Fukui Prefecture","Shiga Prefecture","Toyama Prefecture","Shimane Prefecture","Ibaraki Prefecture","Saitama","Chiba","Shinjuku, Takadanobaba Nakano - Kichijoji","Kyoto","Ebisu, Meguro Shinagawa","Ginza Shinbashi, Tokyo, Ueno","Aichi","Kawasaki, Shonan-Hakone other","Fukuoka","Tochigi","Minami other","Shibuya, Aoyama, Jiyugaoka","Ikebukuro Kagurazaka-Akabane","Akasaka, Roppongi, Azabu","Yokohama","Miyagi","Fukushima","Much","Kochi","Tachikawa Machida, Hachioji other","Hiroshima","Niigata","Okayama","Ehime","Kagawa","Northern","Tokushima","Hyogo","Gifu","Miyazaki","Nagasaki","Ishikawa","Yamagata","Shizuoka","Aomori","Okinawa","Akita","Nagano","Iwate","Kumamoto","Yamaguchi","Saga","Nara","Triple","Gunma","Wakayama","Yamanashi","Tottori","Kagoshima","Fukui","Shiga","Toyama","Shimane","Ibaraki"),
  stringsAsFactors = F)
# Append data with translated columns...
# COUPON_LIST_TRAIN.CSV
coupon_list_train = read.csv("coupon_list_train.csv", as.is=T) # Read data file to translate
names(trans)=c("jp","en_capsule") # Rename column
coupon_list_train=merge(coupon_list_train,trans,by.x="CAPSULE_TEXT",by.y="jp",all.x=T) # Join translation onto original data
names(trans)=c("jp","en_genre"); coupon_list_train=merge(coupon_list_train,trans,by.x="GENRE_NAME",by.y="jp",all.x=T)
names(trans)=c("jp","en_small_area"); coupon_list_train=merge(coupon_list_train,trans,by.x="small_area_name",by.y="jp",all.x=T)
names(trans)=c("jp","en_ken"); coupon_list_train=merge(coupon_list_train,trans,by.x="ken_name",by.y="jp",all.x=T)
names(trans)=c("jp","en_large_area"); coupon_list_train=merge(coupon_list_train,trans,by.x="large_area_name",by.y="jp",all.x=T)
write.csv(coupon_list_train, "coupon_list_train_en.csv", row.names = F)
# COUPON_LIST_TRAIN.CSV
coupon_area_train = read.csv("coupon_area_train.csv", as.is=T) 
names(trans)=c("jp","en_small_area"); coupon_area_train=merge(coupon_area_train,trans,by.x="SMALL_AREA_NAME",by.y="jp",all.x=T)
names(trans)=c("jp","en_pref"); coupon_area_train=merge(coupon_area_train,trans,by.x="PREF_NAME",by.y="jp",all.x=T)
write.csv(coupon_area_train, "coupon_area_train_en.csv", row.names = F)
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiANCg0KVHJ5IGV4ZWN1dGluZyB0aGlzIGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqUnVuKiBidXR0b24gd2l0aGluIHRoZSBjaHVuayBvciBieSBwbGFjaW5nIHlvdXIgY3Vyc29yIGluc2lkZSBpdCBhbmQgcHJlc3NpbmcgKkN0cmwrU2hpZnQrRW50ZXIqLiANCg0KYGBge3J9DQpwbG90KGNhcnMpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGRwbHlyKQ0Kc2V0d2QoIkM6XFxVc2Vyc1xcUmV2YW50aCBLXFxEb2N1bWVudHNcXGNvdXBvbiBwdXJjaGFzZSBwcmVkaWN0aW9uIikNCg0KYGBgDQoNCg0KQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkN0cmwrQWx0K0kqLg0KDQpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkN0cmwrU2hpZnQrSyogdG8gcHJldmlldyB0aGUgSFRNTCBmaWxlKS4NCicnJ3tyfQ0Kc2V0d2QoIkQ6XGFkdmFuY2UgRE1cSEFDS0VSREFZXGNvdXBvbiBwdXJjaGFzZSBwcmVkaWN0aW9uIikNCicnJw0KYGBge3J9DQojcmVhZCBpbiBhbGwgdGhlIGlucHV0IGRhdGENCmNwZHRyIDwtIHJlYWQuY3N2KCJjb3Vwb25fZGV0YWlsX3RyYWluLmNzdiIpDQpjcGx0ciA8LSByZWFkLmNzdigiY291cG9uX2xpc3RfdHJhaW4uY3N2IikNCmNwbHRlIDwtIHJlYWQuY3N2KCJjb3Vwb25fbGlzdF90ZXN0LmNzdiIpDQp1bGlzdCA8LSByZWFkLmNzdigidXNlcl9saXN0LmNzdiIpDQpjcGF0ciA8LSByZWFkLmNzdigiY291cG9uX2FyZWFfdHJhaW4uY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KY3B2dHIgPC0gcmVhZC5jc3YoImNvdXBvbl92aXNpdF90cmFpbi5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpjcGR0ciA8LSByZWFkLmNzdigiY291cG9uX2RldGFpbF90cmFpbi5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpgYGANCg0KYGBge3J9DQpiYXJwbG90KHRhYmxlKHVsaXN0JFNFWF9JRCksDQogICAgICAgIG5hbWVzLmFyZyA9IGMoIkZFTUFMRSIsICJNQUxFIiksbWFpbiA9ICJnZW5kZXIgZGlzdHJpYnV0aWlvbiIsY29sID0gIiNmZmQxZGMiKQ0KYGBgDQoNCmBgYHtyfQ0KaGlzdCh1bGlzdCRBR0UsbWFpbiA9ICJBZ2UtIGRpc3RyaWJ1dGlvbiIseGxhYj0gTlVMTCxjb2w9IiNhZWM2Y2YiKQ0KYGBgDQoNCmBgYHtyfQ0KYWdlX2dyb3VwcyA8LSBjKDIwLCAzMCwgNDAsIDUwLCA2MCwgNzAsIDgwKQ0KdWxpc3QkQUdFX0dST1VQIDwtIGN1dCh1bGlzdCRBR0UsIGFnZV9ncm91cHMsIGluY2x1ZGUubG93ZXN0ID0gVFJVRSkNCnBsb3QodWxpc3QkQUdFX0dST1VQLHVsaXN0JFNFWF9JRCwgbWFpbiA9ICJBZ2UgR3JvdXAgYW5kIEdlbmRlciIsIHhsYWIgPSAiQWdlIEdyb3VwIiwgeWxhYiA9ICJHZW5kZXIiKQ0KDQpgYGANCmBgYHtyfQ0KbmFtZXModWxpc3QpDQpgYGANCg0KYGBge3J9DQpwYXIobWZyb3c9YygxLDEpKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KZ2dwbG90KHVsaXN0LCBhZXMoeD1BR0UsIGZpbGw9U0VYX0lEKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD01LCBwb3NpdGlvbj0iZG9kZ2UiKQ0KDQpgYGANCiMjIyBSZWdpc3RlcmVkIGRhdGUgKGJ5IHNleF9pZA0KYGBge3J9DQojIyMgUmVnaXN0ZXJlZCBkYXRlIChieSBzZXhfaWQNCnVsaXN0JFJFR19EQVRFIDwtIGFzLkRhdGUodWxpc3QkUkVHX0RBVEUpDQp1bGlzdCRXSVRIRFJBV19EQVRFIDwtIGFzLkRhdGUodWxpc3QkV0lUSERSQVdfREFURSkNCg0KZ2dwbG90KHVsaXN0LCBhZXMoeD11bGlzdCRSRUdfREFURSwgZmlsbD1TRVhfSUQpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTI1LCBwb3NpdGlvbj0iZG9kZ2UiKQ0KDQoNCmBgYA0KYGBge3J9DQpnZ3Bsb3QodWxpc3QsIGFlcyh4PXVsaXN0JFdJVEhEUkFXX0RBVEUsIGZpbGw9U0VYX0lEKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0yNSwgcG9zaXRpb249ImRvZGdlIikNCg0KIA0KYGBgDQoNCiMjIyBNZW1iZXJzaGlwIGR1cmF0aW9uDQoNCmBgYHtyfQ0KdWxpc3QkTEFTVF9EQVRFIDwtIHVsaXN0JFdJVEhEUkFXX0RBVEUNCnVsaXN0W2lzLm5hKHVsaXN0JExBU1RfREFURSksXSRMQVNUX0RBVEUgPC0gbWF4KHVsaXN0W2lzLm5hKHVsaXN0JFdJVEhEUkFXX0RBVEUpID09IEZBTFNFLF0kV0lUSERSQVdfREFURSkNCnVsaXN0JERVUkFUSU9OIDwtIHVsaXN0JExBU1RfREFURSAtIHVsaXN0JFJFR19EQVRFDQp1bGlzdCREVVJBVElPTiA8LSBhcy5udW1lcmljKHVsaXN0JERVUkFUSU9OLCB1bml0cyA9ICJkYXlzIikNCg0Kc3VtbWFyeSh1bGlzdCREVVJBVElPTikNCg0KZ2dwbG90KHVsaXN0LCBhZXMoeD11bGlzdCREVVJBVElPTiwgZmlsbD1TRVhfSUQpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTI1LCBwb3NpdGlvbj0iZG9kZ2UiKQ0KYGBgDQoNCmBgYHtyfQ0KdXNlcl9mcmVxdWVuY3kgPSBhcy5kYXRhLmZyYW1lLnRhYmxlKHNvcnQodGFibGUodWxpc3QkUFJFRl9OQU1FKSkpDQpjb2xuYW1lcyh1c2VyX2ZyZXF1ZW5jeSkgPC0gYygiUFJFRl9OQU1FIiwgIkZSRVFVRU5DWSIpDQoNCnByaW50KHVzZXJfZnJlcXVlbmN5KQ0KDQpgYGANCmBgYHtyfQ0KY3B2dHIkc2V4ID0gdWxpc3RbbWF0Y2goY3B2dHIkVVNFUl9JRF9oYXNoLHVsaXN0JFVTRVJfSURfaGFzaCksIlNFWF9JRCJdDQpwdXJjaGFzZWRfZ2VuZGVyIDwtIHRhYmxlKGNwdnRyJFBVUkNIQVNFX0ZMRyxjcHZ0ciRzZXgpDQoNCmBgYA0KI2NvdXBvbiB1c2VybGlzdCBkYXRhIGV4cGxvcmF0aW9uDQpgYGB7cn0NCmJhcnBsb3QocHJvcC50YWJsZShwdXJjaGFzZWRfZ2VuZGVyLDEpLCBsZWdlbmQudGV4dCA9IFRSVUUsDQogICAgICAgIG1haW4gPSAiUHVyY2hhZ2VzIGJ5IEdlbmRlciIsIA0KICAgICAgICBjb2wgPSBjKCJyZWQiLCJ5ZWxsb3ciKSwNCiAgICAgICAgYmVzaWRlID0gVFJVRSwNCiAgICAgICAgeGxhYiA9ICJQdXJjaGFzZWQiLA0KICAgICAgICB5bGFiID0gIlByb3BvcnRpb24iKQ0KDQpgYGANCg0KYGBge3J9DQpjcHZ0ciRhZ2UgPSB1bGlzdFttYXRjaChjcHZ0ciRVU0VSX0lEX2hhc2gsdWxpc3QkVVNFUl9JRF9oYXNoKSwiQUdFIl0NCg0KcHVyY2hhc2VkX2FnZSA8LSB0YWJsZShjcHZ0ciRQVVJDSEFTRV9GTEcsY3V0KGNwdnRyJGFnZSxicmVha3MgPSBzZXEoMTAsMTAwLGJ5PTEwKSkpDQoNCg0KYGBgDQpgYGB7cn0NCmJhcnBsb3QocHVyY2hhc2VkX2FnZSwgbGVnZW5kLnRleHQgPSBUUlVFLA0KICAgICAgICBtYWluID0gIlB1cmNoYWdlcyBieSBBZ2UiLCANCiAgICAgICAgY29sID0gYygicmVkIiwieWVsbG93IiksDQogICAgICAgIGJlc2lkZSA9IFRSVUUsDQogICAgICAgIHhsYWIgPSAiUHVyY2hhc2VkIiwNCiAgICAgICAgeWxhYiA9ICJQcm9wb3J0aW9uIikNCg0KYGBgDQoNCmBgYHtyfQ0KY3BkdHIkYWdlID0gdWxpc3RbbWF0Y2goY3BkdHIkVVNFUl9JRF9oYXNoLHVsaXN0JFVTRVJfSURfaGFzaCksIkFHRSJdDQoNCg0Kc3Vic2V0X2FnZV8xMCA9IGNwZHRyWyhhcy5udW1lcmljKGNwZHRyJGFnZSkgPiAxMA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICYgYXMubnVtZXJpYyhjcGR0ciRhZ2UpIDw9IDIwKSAsXQ0KDQoNCmBgYA0KYGBge3J9DQpwaWUodGFibGUoc3Vic2V0X2FnZV8xMCRDT1VQT05fSURfaGFzaCkpDQoNCmBgYA0KYGBge3J9DQpzdWJzZXRfYWdlXzIwID0gY3BkdHJbKGFzLm51bWVyaWMoY3BkdHIkYWdlKSA+IDIwDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJiBhcy5udW1lcmljKGNwZHRyJGFnZSkgPD0gMzApICxdDQoNCnBpZSh0YWJsZShzdWJzZXRfYWdlXzIwJENPVVBPTl9JRF9oYXNoKSkNCg0KYGBgDQoNCmBgYHtyfQ0Kc3Vic2V0X2FnZV8zMCA9IGNwZHRyWyhhcy5udW1lcmljKGNwZHRyJGFnZSkgPiAzMA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICYgYXMubnVtZXJpYyhjcGR0ciRhZ2UpIDw9IDQwKSAsXQ0KDQpwaWUodGFibGUoc3Vic2V0X2FnZV8zMCRDT1VQT05fSURfaGFzaCkpDQoNCmBgYA0KDQpgYGB7cn0NCnN1YnNldF9hZ2VfNDAgPSBjcGR0clsoYXMubnVtZXJpYyhjcGR0ciRhZ2UpID4gNDANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAmIGFzLm51bWVyaWMoY3BkdHIkYWdlKSA8PSA1MCkgLF0NCg0KcGllKHRhYmxlKHN1YnNldF9hZ2VfNDAkQ09VUE9OX0lEX2hhc2gpKQ0KDQpgYGANCg0KYGBge3J9DQpzdWJzZXRfYWdlXzUwID0gY3BkdHJbKGFzLm51bWVyaWMoY3BkdHIkYWdlKSA+IDUwDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJiBhcy5udW1lcmljKGNwZHRyJGFnZSkgPD0gNjApICxdDQoNCnBpZSh0YWJsZShzdWJzZXRfYWdlXzUwJENPVVBPTl9JRF9oYXNoKSkNCg0KYGBgDQoNCmBgYHtyfQ0Kc3Vic2V0X2FnZV82MCA9IGNwZHRyWyhhcy5udW1lcmljKGNwZHRyJGFnZSkgPiA2MA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICYgYXMubnVtZXJpYyhjcGR0ciRhZ2UpIDw9IDcwKSAsXQ0KDQpwaWUodGFibGUoc3Vic2V0X2FnZV82MCRDT1VQT05fSURfaGFzaCkpDQoNCmBgYA0KDQpgYGB7cn0NCnN1YnNldF9hZ2VfNzAgPSBjcGR0clsoYXMubnVtZXJpYyhjcGR0ciRhZ2UpID4gNzApICxdDQoNCnBpZSh0YWJsZShzdWJzZXRfYWdlXzcwJENPVVBPTl9JRF9oYXNoKSkNCg0KYGBgDQpgYGB7cn0NCiMjIyBDb3Vwb24gTGlzdA0KDQoNCg0KYmFycGxvdCh0YWJsZShjcGx0ciRVU0FCTEVfREFURV9NT04pLA0KIyBuYW1lcy5hcmdzID0gYygiTm8iLCAiWWVzIikNCm1haW4gPSAiQ291cG9uIHVzYWJsZSBvbiBNb25kYXk/IiwNCmNvbCA9ICIjZmRmZDk2IikNCg0KDQpgYGANCmBgYHtyfQ0KYmFycGxvdCh0YWJsZShjcGx0ciRVU0FCTEVfREFURV9UVUUpLA0KICAgICAgICANCiAgICAgICAgbWFpbiA9ICJDb3Vwb24gdXNhYmxlIG9uIFR1ZXNkYXk/IiwNCiAgICAgICAgY29sID0gIiNmZGZkOTYiKQ0KDQpgYGANCg0KYGBge3J9DQpiYXJwbG90KHRhYmxlKGNwbHRyJFVTQUJMRV9EQVRFX1dFRCksDQogICAgICAgIA0KICAgICAgICBtYWluID0gIkNvdXBvbiB1c2FibGUgb24gV2VkbmVzZGF5PyIsDQogICAgICAgIGNvbCA9ICIjZmRmZDk2IikNCg0KYGBgDQpgYGB7cn0NCmJhcnBsb3QodGFibGUoY3BsdHIkVVNBQkxFX0RBVEVfVEhVKSwNCiAgICAgICAgDQogICAgICAgIG1haW4gPSAiQ291cG9uIHVzYWJsZSBvbiBUaHVyc2RheT8iLA0KICAgICAgICBjb2wgPSAiI2ZkZmQ5NiIpDQoNCg0KYGBgDQoNCmBgYHtyfQ0KYmFycGxvdCh0YWJsZShjcGx0ciRVU0FCTEVfREFURV9GUkkpLA0KICAgICAgICANCiAgICAgICAgbWFpbiA9ICJDb3Vwb24gdXNhYmxlIG9uIEZyaWRheT8iLA0KICAgICAgICBjb2wgPSAiI2ZkZmQ5NiIpDQoNCg0KYGBgDQoNCmBgYHtyfQ0KYmFycGxvdCh0YWJsZShjcGx0ciRVU0FCTEVfREFURV9TQVQpLA0KICAgICAgICANCiAgICAgICAgbWFpbiA9ICJDb3Vwb24gdXNhYmxlIG9uIFNhdHVyZGF5PyIsDQogICAgICAgIGNvbCA9ICIjZmRmZDk2IikNCg0KYGBgDQoNCmBgYHtyfQ0KYmFycGxvdCh0YWJsZShjcGx0ciRVU0FCTEVfREFURV9TVU4pLA0KICAgICAgICANCiAgICAgICAgbWFpbiA9ICJDb3Vwb24gdXNhYmxlIG9uIFN1bmRheT8iLA0KICAgICAgICBjb2wgPSAiI2ZkZmQ5NiIpDQpgYGANCg0KVGhlIERJU0NPVU5UIFBSSUNFIHNlZW1zIGludGVyZXN0aW5nIHRvbywgYXMgY29tbW9ucyBzdHJhdGVneSB0byBhdHRyYWN0IGJ1eWVycyBpcyB0byBzaG93IGxhcmdlIGRpc2NvdW50cy4gVGhlIG91dGxpZXIga2luZCBvZiBkaXN0b3J0cyB0aGlzIGdyYXBoLCB0aG91Z2guDQoNCmBgYHtyfQ0KZ2dwbG90KGNwbHRyLCBhZXMoeCA9IENBVEFMT0dfUFJJQ0UsIHkgPSBESVNDT1VOVF9QUklDRSkpICsgZ2VvbV9wb2ludCgpICsgDQogIGxhYnMoeCA9ICJDYXRhbG9ndWUgUHJpY2UiLCB5ID0gIkRpc2NvdW50IFByaWNlIiwgdGl0bGUgPSAiQ2F0YWxvZ3VlIGFuZCBEaXNjb3VudCBQcmljZXMiKQ0KDQpgYGANCg0KIyMjIENvdXBvbiBBcmVhDQoNCkNvdXBvbnMgYXJlIGxpc3RlZCBpbiBkaWZmZXJlbnQgcHJlZmVjdHVyZXMgKHN0YXRlcykuDQoNCmBgYHtyfQ0KYmFycGxvdCh0YWJsZShjcGF0ciRQUkVGX05BTUUpLA0KICAgICAgICBtYWluID0gIkNvdXBvbiBMaXN0aW5nIEFyZWFzIChQcmVmZWN0dXJlcykiKQ0KY291cG9uUHJlZmVjdHVyZXMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShjcGF0ciRQUkVGX05BTUUpKQ0KY29sbmFtZXMoY291cG9uUHJlZmVjdHVyZXMpIDwtIGMoIlByZWZlY3R1cmUiLCAiRnJlcXVlbmN5IikNCmFycmFuZ2UoY291cG9uUHJlZmVjdHVyZXMsIGRlc2MoRnJlcXVlbmN5KSkNCg0KYGBgDQoNCmBgYHtyfQ0KI21ha2luZyBvZiB0aGUgdHJhaW4gc2V0DQp0cmFpbiA8LSBtZXJnZShjcGR0cixjcGx0cikNCmBgYA0KDQpgYGB7cn0NCnRyYWluIDwtIHRyYWluWyxjKCJDT1VQT05fSURfaGFzaCIsIlVTRVJfSURfaGFzaCIsDQogICAgICAgICAgICAgICAgICAiR0VOUkVfTkFNRSIsIkRJU0NPVU5UX1BSSUNFIiwiUFJJQ0VfUkFURSIsDQogICAgICAgICAgICAgICAgICAiVVNBQkxFX0RBVEVfTU9OIiwiVVNBQkxFX0RBVEVfVFVFIiwiVVNBQkxFX0RBVEVfV0VEIiwiVVNBQkxFX0RBVEVfVEhVIiwNCiAgICAgICAgICAgICAgICAgICJVU0FCTEVfREFURV9GUkkiLCJVU0FCTEVfREFURV9TQVQiLCJVU0FCTEVfREFURV9TVU4iLCJVU0FCTEVfREFURV9IT0xJREFZIiwNCiAgICAgICAgICAgICAgICAgICJVU0FCTEVfREFURV9CRUZPUkVfSE9MSURBWSIsImxhcmdlX2FyZWFfbmFtZSIsImtlbl9uYW1lIiwic21hbGxfYXJlYV9uYW1lIildDQoNCg0KYGBgDQoNCmBgYHtyfQ0KI2NvbWJpbmUgdGhlIHRlc3Qgc2V0IHdpdGggdGhlIHRyYWluDQpjcGx0ZSRVU0VSX0lEX2hhc2ggPC0gImR1bW15dXNlciINCmNwY2hhciA8LSBjcGx0ZVssYygiQ09VUE9OX0lEX2hhc2giLCJVU0VSX0lEX2hhc2giLA0KICAgICAgICAgICAgICAgICAgICJHRU5SRV9OQU1FIiwiRElTQ09VTlRfUFJJQ0UiLCJQUklDRV9SQVRFIiwNCiAgICAgICAgICAgICAgICAgICAiVVNBQkxFX0RBVEVfTU9OIiwiVVNBQkxFX0RBVEVfVFVFIiwiVVNBQkxFX0RBVEVfV0VEIiwiVVNBQkxFX0RBVEVfVEhVIiwNCiAgICAgICAgICAgICAgICAgICAiVVNBQkxFX0RBVEVfRlJJIiwiVVNBQkxFX0RBVEVfU0FUIiwiVVNBQkxFX0RBVEVfU1VOIiwiVVNBQkxFX0RBVEVfSE9MSURBWSIsDQogICAgICAgICAgICAgICAgICAgIlVTQUJMRV9EQVRFX0JFRk9SRV9IT0xJREFZIiwibGFyZ2VfYXJlYV9uYW1lIiwia2VuX25hbWUiLCJzbWFsbF9hcmVhX25hbWUiKV0NCnRyYWluIDwtIHJiaW5kKHRyYWluLGNwY2hhcikNCg0KDQpgYGANCg0KYGBge3J9DQojTkEgaW1wdXRhdGlvbg0KdHJhaW5baXMubmEodHJhaW4pXSA8LSAxDQoNCmBgYA0KYGBge3J9DQojZmVhdHVyZSBlbmdpbmVlcmluZw0KdHJhaW4kRElTQ09VTlRfUFJJQ0UgPC0gMS9sb2cxMCh0cmFpbiRESVNDT1VOVF9QUklDRSkNCnRyYWluJFBSSUNFX1JBVEUgPC0gKHRyYWluJFBSSUNFX1JBVEUqdHJhaW4kUFJJQ0VfUkFURSkvKDEwMCoxMDApDQoNCmBgYA0KYGBge3J9DQojY29udmVydCB0aGUgZmFjdG9ycyB0byBjb2x1bW5zIG9mIDAncyBhbmQgMSdzDQp0cmFpbiA8LSBjYmluZCh0cmFpblssYygxLDIpXSxtb2RlbC5tYXRyaXgofiAtMSArIC4sdHJhaW5bLC1jKDEsMildLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0cy5hcmc9bGFwcGx5KHRyYWluWyxuYW1lcyh3aGljaChzYXBwbHkodHJhaW5bLC1jKDEsMildLCBpcy5mYWN0b3IpPT1UUlVFKSldLCBjb250cmFzdHMsIGNvbnRyYXN0cz1GQUxTRSkpKQ0KDQpgYGANCg0KYGBge3J9DQojc2VwYXJhdGUgdGhlIHRlc3QgZnJvbSB0cmFpbg0KdGVzdCA8LSB0cmFpblt0cmFpbiRVU0VSX0lEX2hhc2g9PSJkdW1teXVzZXIiLF0NCnRlc3QgPC0gdGVzdFssLTJdDQp0cmFpbiA8LSB0cmFpblt0cmFpbiRVU0VSX0lEX2hhc2ghPSJkdW1teXVzZXIiLF0NCg0KYGBgDQpgYGB7cn0NCiNkYXRhIGZyYW1lIG9mIHVzZXIgY2hhcmFjdGVyaXN0aWNzDQp1Y2hhciA8LSBhZ2dyZWdhdGUoLn5VU0VSX0lEX2hhc2gsIGRhdGE9dHJhaW5bLC0xXSxGVU49bWVhbikNCnVjaGFyJERJU0NPVU5UX1BSSUNFIDwtIDENCnVjaGFyJFBSSUNFX1JBVEUgPC0gMQ0KDQpgYGANCmBgYHtyfQ0KI1dlaWdodCBNYXRyaXg6IEdFTlJFX05BTUUgRElTQ09VTlRfUFJJQ0UgUFJJQ0VfUkFURSBVU0FCTEVfREFURV8gbGFyZ2VfYXJlYV9uYW1lIGtlbl9uYW1lIHNtYWxsX2FyZWFfbmFtZQ0KbGlicmFyeShNYXRyaXgpDQpyZXF1aXJlKE1hdHJpeCkNCg0KVyA8LSBhcy5tYXRyaXgoRGlhZ29uYWwoeD1jKHJlcCgyLjA1LDEzKSwgcmVwKDIsMSksIHJlcCgtMC4xMywxKSwgcmVwKDAsOSksIHJlcCgwLjUsOSksIHJlcCgxLjAxLDQ3KSwgcmVwKDQuNzUsNTUpKSkpDQpgYGANCmBgYHtyfQ0KIyBXZSBhcmUgZ29pbmd0byBsZWFybiAgaXMgaG93IHRvIHVzZSBhIHdlbGwta25vd24gc2ltaWxhcml0eSBtZWFzdXJlIChDb3NpbmUgc2ltaWxhcml0eSkgdG8gY2xhY3VhbHRlIHRoZSBzaW1pbGFyaXR5IGJldHdlZW4gZGlmZmVyZW50IGNvdXBvbnMNCiNTVEVQMTogY29udmVyIHRoZSBkYXQgdG8gZG90IHByb2R1Y3QgaW4gbWF0cml4IGZvcm1hdA0KIyBTVEVQMjoNCiNjYWxjdWxhdGlvbiBvZiBjb3NpbmUgc2ltaWxhaXJ0aWVzIG9mIHVzZXJzIGFuZCBjb3Vwb25zDQpzY29yZSA9IGFzLm1hdHJpeCh1Y2hhclssMjpuY29sKHVjaGFyKV0pICUqJSBXICUqJSB0KGFzLm1hdHJpeCh0ZXN0WywyOm5jb2wodGVzdCldKSkNCg0KYGBgDQpgYGB7cn0NCiNvcmRlciB0aGUgbGlzdCBvZiBjb3Vwb25zIGFjY29yZGluZyB0byBzaW1pbGFpcnRpZXMgYW5kIHRha2Ugb25seSBmaXJzdCAxMCBjb3Vwb25zDQp1Y2hhciRQVVJDSEFTRURfQ09VUE9OUyA8LSBkby5jYWxsKHJiaW5kLCBsYXBwbHkoMTpucm93KHVjaGFyKSxGVU49ZnVuY3Rpb24oaSl7DQogIHB1cmNoYXNlZF9jcCA8LSBwYXN0ZSh0ZXN0JENPVVBPTl9JRF9oYXNoW29yZGVyKHNjb3JlW2ksXSwgZGVjcmVhc2luZyA9IFRSVUUpXVsxOjEwXSxjb2xsYXBzZT0iICIpDQogIHJldHVybihwdXJjaGFzZWRfY3ApDQp9KSkNCg0KYGBgDQoNCmBgYHtyfQ0KI21ha2Ugc3VibWlzc2lvbg0Kc3VibWlzc2lvbiA8LSBtZXJnZSh1bGlzdCwgdWNoYXIsIGFsbC54PVRSVUUpDQpzdWJtaXNzaW9uIDwtIHN1Ym1pc3Npb25bLGMoIlVTRVJfSURfaGFzaCIsIlBVUkNIQVNFRF9DT1VQT05TIildDQp3cml0ZS5jc3Yoc3VibWlzc2lvbiwgZmlsZT0iY29zaW5lX3NpbS5jc3YiLCByb3cubmFtZXM9RkFMU0UpDQpgYGANCg0KYGBge3J9DQojIENyZWF0ZSBtYXN0ZXIgdHJhbnNsYXRpb24gdGFibGUgZnJvbSBKYXBhbmVzZSB0byBFbmdsaXNoDQpjb3Vwb25fbGlzdF90cmFpbiA9IHJlYWQuY3N2KCJjb3Vwb25fbGlzdF90cmFpbi5jc3YiLCBhcy5pcz1UKSAjIFNvdXJjZSBmaWxlIHRoZSBFbmdsaXNoIGxpc3QgaXMga2V5ZWQgYnkNCnRyYW5zID0gZGF0YS5mcmFtZSgNCiAganA9dW5pcXVlKGMoY291cG9uX2xpc3RfdHJhaW4kR0VOUkVfTkFNRSwgY291cG9uX2xpc3RfdHJhaW4kQ0FQU1VMRV9URVhULA0KICAgICAgICAgICAgICBjb3Vwb25fbGlzdF90cmFpbiRsYXJnZV9hcmVhX25hbWUsIGNvdXBvbl9saXN0X3RyYWluJGtlbl9uYW1lLA0KICAgICAgICAgICAgICBjb3Vwb25fbGlzdF90cmFpbiRzbWFsbF9hcmVhX25hbWUpKSwNCiAgZW49YygiRm9vZCIsIkhhaXIgc2Fsb24iLCJTcGEiLCJSZWxheGF0aW9uIiwiQmVhdXR5IiwiTmFpbCBhbmQgZXllIHNhbG9uIiwiRGVsaXZlcnkgc2VydmljZSIsIkxlc3NvbiIsIkdpZnQgY2FyZCIsIk90aGVyIGNvdXBvbiIsIkxlaXN1cmUiLCJIb3RlbCBhbmQgSmFwYW5lc2UgaG90ZWwiLCJIZWFsdGggYW5kIG1lZGljYWwiLCJPdGhlciIsIkhvdGVsIiwiSmFwYW5lc2UgaG90ZWwiLCJWYWNhdGlvbiByZW50YWwiLCJMb2RnZSIsIlJlc29ydCBpbm4iLCJHdWVzdCBob3VzZSIsIkphcGFuc2UgZ3Vlc3QgaG91c2UiLCJQdWJsaWMgaG90ZWwiLCJCZWF1dHkiLCJFdmVudCIsIldlYiBzZXJ2aWNlIiwiQ2xhc3MiLCJDb3JyZXNwb25kZW5jZSBjb3Vyc2UiLCJLYW50byIsIkthbnNhaSIsIkVhc3QgU2VhIiwiSG9ra2FpZG8iLCJLeXVzaHUtT2tpbmF3YSIsIk5vcnRoZWFzdCIsIlNoaWtva3UiLCJDaHVnb2t1IiwiSG9rdXNoaW5ldHN1IiwiU2FpdGFtYSBQcmVmZWN0dXJlIiwiQ2hpYmEgUHJlZmVjdHVyZSIsIlRva3lvIiwiS3lvdG8iLCJBaWNoaSBQcmVmZWN0dXJlIiwiS2FuYWdhd2EgUHJlZmVjdHVyZSIsIkZ1a3Vva2EgUHJlZmVjdHVyZSIsIlRvY2hpZ2kgUHJlZmVjdHVyZSIsIk9zYWthIHByZWZlY3R1cmUiLCJNaXlhZ2kgUHJlZmVjdHVyZSIsIkZ1a3VzaGltYSBQcmVmZWN0dXJlIiwiT2l0YSBQcmVmZWN0dXJlIiwiS29jaGkgUHJlZmVjdHVyZSIsIkhpcm9zaGltYSBQcmVmZWN0dXJlIiwiTmlpZ2F0YSBQcmVmZWN0dXJlIiwiT2theWFtYSBQcmVmZWN0dXJlIiwiRWhpbWUgUHJlZmVjdHVyZSIsIkthZ2F3YSBQcmVmZWN0dXJlIiwiVG9rdXNoaW1hIFByZWZlY3R1cmUiLCJIeW9nbyBQcmVmZWN0dXJlIiwiR2lmdSBQcmVmZWN0dXJlIiwiTWl5YXpha2kgUHJlZmVjdHVyZSIsIk5hZ2FzYWtpIFByZWZlY3R1cmUiLCJJc2hpa2F3YSBQcmVmZWN0dXJlIiwiWWFtYWdhdGEgUHJlZmVjdHVyZSIsIlNoaXp1b2thIFByZWZlY3R1cmUiLCJBb21vcmkgUHJlZmVjdHVyZSIsIk9raW5hd2EiLCJBa2l0YSIsIk5hZ2FubyBQcmVmZWN0dXJlIiwiSXdhdGUgUHJlZmVjdHVyZSIsIkt1bWFtb3RvIFByZWZlY3R1cmUiLCJZYW1hZ3VjaGkgUHJlZmVjdHVyZSIsIlNhZ2EgUHJlZmVjdHVyZSIsIk5hcmEgUHJlZmVjdHVyZSIsIk1pZSIsIkd1bm1hIFByZWZlY3R1cmUiLCJXYWtheWFtYSBQcmVmZWN0dXJlIiwiWWFtYW5hc2hpIFByZWZlY3R1cmUiLCJUb3R0b3JpIFByZWZlY3R1cmUiLCJLYWdvc2hpbWEgcHJlZmVjdHVyZSIsIkZ1a3VpIFByZWZlY3R1cmUiLCJTaGlnYSBQcmVmZWN0dXJlIiwiVG95YW1hIFByZWZlY3R1cmUiLCJTaGltYW5lIFByZWZlY3R1cmUiLCJJYmFyYWtpIFByZWZlY3R1cmUiLCJTYWl0YW1hIiwiQ2hpYmEiLCJTaGluanVrdSwgVGFrYWRhbm9iYWJhIE5ha2FubyAtIEtpY2hpam9qaSIsIkt5b3RvIiwiRWJpc3UsIE1lZ3VybyBTaGluYWdhd2EiLCJHaW56YSBTaGluYmFzaGksIFRva3lvLCBVZW5vIiwiQWljaGkiLCJLYXdhc2FraSwgU2hvbmFuLUhha29uZSBvdGhlciIsIkZ1a3Vva2EiLCJUb2NoaWdpIiwiTWluYW1pIG90aGVyIiwiU2hpYnV5YSwgQW95YW1hLCBKaXl1Z2Fva2EiLCJJa2VidWt1cm8gS2FndXJhemFrYS1Ba2FiYW5lIiwiQWthc2FrYSwgUm9wcG9uZ2ksIEF6YWJ1IiwiWW9rb2hhbWEiLCJNaXlhZ2kiLCJGdWt1c2hpbWEiLCJNdWNoIiwiS29jaGkiLCJUYWNoaWthd2EgTWFjaGlkYSwgSGFjaGlvamkgb3RoZXIiLCJIaXJvc2hpbWEiLCJOaWlnYXRhIiwiT2theWFtYSIsIkVoaW1lIiwiS2FnYXdhIiwiTm9ydGhlcm4iLCJUb2t1c2hpbWEiLCJIeW9nbyIsIkdpZnUiLCJNaXlhemFraSIsIk5hZ2FzYWtpIiwiSXNoaWthd2EiLCJZYW1hZ2F0YSIsIlNoaXp1b2thIiwiQW9tb3JpIiwiT2tpbmF3YSIsIkFraXRhIiwiTmFnYW5vIiwiSXdhdGUiLCJLdW1hbW90byIsIllhbWFndWNoaSIsIlNhZ2EiLCJOYXJhIiwiVHJpcGxlIiwiR3VubWEiLCJXYWtheWFtYSIsIllhbWFuYXNoaSIsIlRvdHRvcmkiLCJLYWdvc2hpbWEiLCJGdWt1aSIsIlNoaWdhIiwiVG95YW1hIiwiU2hpbWFuZSIsIkliYXJha2kiKSwNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpDQoNCmBgYA0KYGBge3J9DQojIEFwcGVuZCBkYXRhIHdpdGggdHJhbnNsYXRlZCBjb2x1bW5zLi4uDQoNCiMgQ09VUE9OX0xJU1RfVFJBSU4uQ1NWDQpjb3Vwb25fbGlzdF90cmFpbiA9IHJlYWQuY3N2KCJjb3Vwb25fbGlzdF90cmFpbi5jc3YiLCBhcy5pcz1UKSAjIFJlYWQgZGF0YSBmaWxlIHRvIHRyYW5zbGF0ZQ0KbmFtZXModHJhbnMpPWMoImpwIiwiZW5fY2Fwc3VsZSIpICMgUmVuYW1lIGNvbHVtbg0KY291cG9uX2xpc3RfdHJhaW49bWVyZ2UoY291cG9uX2xpc3RfdHJhaW4sdHJhbnMsYnkueD0iQ0FQU1VMRV9URVhUIixieS55PSJqcCIsYWxsLng9VCkgIyBKb2luIHRyYW5zbGF0aW9uIG9udG8gb3JpZ2luYWwgZGF0YQ0KbmFtZXModHJhbnMpPWMoImpwIiwiZW5fZ2VucmUiKTsgY291cG9uX2xpc3RfdHJhaW49bWVyZ2UoY291cG9uX2xpc3RfdHJhaW4sdHJhbnMsYnkueD0iR0VOUkVfTkFNRSIsYnkueT0ianAiLGFsbC54PVQpDQpuYW1lcyh0cmFucyk9YygianAiLCJlbl9zbWFsbF9hcmVhIik7IGNvdXBvbl9saXN0X3RyYWluPW1lcmdlKGNvdXBvbl9saXN0X3RyYWluLHRyYW5zLGJ5Lng9InNtYWxsX2FyZWFfbmFtZSIsYnkueT0ianAiLGFsbC54PVQpDQpuYW1lcyh0cmFucyk9YygianAiLCJlbl9rZW4iKTsgY291cG9uX2xpc3RfdHJhaW49bWVyZ2UoY291cG9uX2xpc3RfdHJhaW4sdHJhbnMsYnkueD0ia2VuX25hbWUiLGJ5Lnk9ImpwIixhbGwueD1UKQ0KbmFtZXModHJhbnMpPWMoImpwIiwiZW5fbGFyZ2VfYXJlYSIpOyBjb3Vwb25fbGlzdF90cmFpbj1tZXJnZShjb3Vwb25fbGlzdF90cmFpbix0cmFucyxieS54PSJsYXJnZV9hcmVhX25hbWUiLGJ5Lnk9ImpwIixhbGwueD1UKQ0Kd3JpdGUuY3N2KGNvdXBvbl9saXN0X3RyYWluLCAiY291cG9uX2xpc3RfdHJhaW5fZW4uY3N2Iiwgcm93Lm5hbWVzID0gRikNCg0KDQpgYGANCmBgYHtyfQ0KIyBDT1VQT05fTElTVF9UUkFJTi5DU1YNCmNvdXBvbl9hcmVhX3RyYWluID0gcmVhZC5jc3YoImNvdXBvbl9hcmVhX3RyYWluLmNzdiIsIGFzLmlzPVQpIA0KbmFtZXModHJhbnMpPWMoImpwIiwiZW5fc21hbGxfYXJlYSIpOyBjb3Vwb25fYXJlYV90cmFpbj1tZXJnZShjb3Vwb25fYXJlYV90cmFpbix0cmFucyxieS54PSJTTUFMTF9BUkVBX05BTUUiLGJ5Lnk9ImpwIixhbGwueD1UKQ0KbmFtZXModHJhbnMpPWMoImpwIiwiZW5fcHJlZiIpOyBjb3Vwb25fYXJlYV90cmFpbj1tZXJnZShjb3Vwb25fYXJlYV90cmFpbix0cmFucyxieS54PSJQUkVGX05BTUUiLGJ5Lnk9ImpwIixhbGwueD1UKQ0Kd3JpdGUuY3N2KGNvdXBvbl9hcmVhX3RyYWluLCAiY291cG9uX2FyZWFfdHJhaW5fZW4uY3N2Iiwgcm93Lm5hbWVzID0gRikNCg0KYGBgDQoNCg==